`timescale 1ns / 1ps


module ALU#(parameter D_WIDTH=34, OPCODE_WIDTH = 5)
(
	input clk,
	input [D_WIDTH-1:0] d0_i,
	input [D_WIDTH-1:0] d1_i,
	input [OPCODE_WIDTH-1:0] control,
	output [D_WIDTH-1:0] d_o
);

////////////////////////////////////////////////////////////////////////
// local param

localparam LD 	= 5'd1;
localparam ST 	= 5'd2;
localparam ADD 	= 5'd3;
localparam SUB 	= 5'd4;
localparam SLL 	= 5'd5;
localparam SRL 	= 5'd6;
localparam AND 	= 5'd7;
localparam OR 	= 5'd8;
localparam NOR	= 5'd9;
localparam XNOR = 5'd10;
localparam IN   = 5'd11;
localparam OUT  = 5'd12;
localparam MOV	= 5'd14;
localparam MOVI = 5'd15;

////////////////////////////////////////////////////////////////////////
// reg

reg [D_WIDTH-1:0] ld_o;
reg [D_WIDTH-1:0] st_o;
reg [D_WIDTH-1:0] add_o;
reg [D_WIDTH-1:0] sub_o;
reg [D_WIDTH-1:0] sll_o;
reg [D_WIDTH-1:0] srl_o;
reg [D_WIDTH-1:0] and_o;
reg [D_WIDTH-1:0] or_o;
reg [D_WIDTH-1:0] nor_o;
reg [D_WIDTH-1:0] xnor_o;

////////////////////////////////////////////////////////////////////////
// reg

reg [D_WIDTH-1:0] out_r;

////////////////////////////////////////////////////////////////////////

adder_backend ld
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(ld_o)
);

////////////////////////////////////////////////////////////////////////

adder_backend st
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(st_o)
);

////////////////////////////////////////////////////////////////////////

adder_backend add
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(add_o)
);

////////////////////////////////////////////////////////////////////////

subtractor sub
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(sub_o)
);

////////////////////////////////////////////////////////////////////////

shiftleft sll
(
	.d_i(d0_i),
	.d_shift(d1_i),
	.d_o(sll_o)
);

////////////////////////////////////////////////////////////////////////

shiftright srl
(
	.d_i(d0_i),
	.d_shift(d1_i),
	.d_o(srl_o)
);

////////////////////////////////////////////////////////////////////////

and_module and_mod
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(and_o)
);

////////////////////////////////////////////////////////////////////////

or_module or_mod
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(or_o)
);

////////////////////////////////////////////////////////////////////////

nor_module nor_mod
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(nor_o)
);

////////////////////////////////////////////////////////////////////////

xnor_module xnor_mod
(
	.d0_i(d0_i),
	.d1_i(d1_i),
	.d_o(xnor_o)
);

////////////////////////////////////////////////////////////////////////

always_ff @(posedge clk)
begin
	case(control)
	LD:
		out_r <= ld_o;
	ST:
		out_r <= st_o;
	ADD:
		out_r <= add_o;
	SUB:
		out_r <= sub_o;
	SLL:
		out_r <= sll_o;
	SRL:
		out_r <= srl_o;
	AND:
		out_r <= and_o;
	OR:
		out_r <= or_o;
	NOR:
		out_r <= nor_o;
	XNOR:
		out_r <= xnor_o;
	IN:
		out_r <= d0_i;
	OUT:
		out_r <= d0_i;
	MOV:
		out_r <= d0_i;		// move register to register
	MOVI:
		out_r <= d1_i;		// move immediate to register
	default:
		out_r <= d0_i;
		
endcase
end

////////////////////////////////////////////////////////////////////////
// assign 

	assign d_o = out_r;

////////////////////////////////////////////////////////////////////////

endmodule

